trigger User_CycleTeamSync on User (after insert, after update)
{
    list<Assignment_Groups__c> agsMasterUpdates = new list<Assignment_Groups__c>();
    Map<String,String> agMap = new Map<String,String>();
    Map<String, User> userIdMap = new Map<String, User>();

    Set<String> userIds = new Set<String>();
    try
    {  
        for (User user : Trigger.new)
        {
           userIds.add(user.id);
           userIdMap.put(user.id, user);
        }
        try
        {
           User user;
           list<Assignment_Groups__c> ags = [select id, User__c, Cycle_team__c from Assignment_Groups__c where User__c in :userIds];
           for (Assignment_Groups__c ag : ags)
           {
               user = userIdMap.get(ag.User__c);
               if (ag.Cycle_Team__c != user.Cycle_Team__c)
               {
                   // last update wins resolution semantics
                   agMap.put(ag.id, user.Cycle_Team__c);
               }    
           } 
        }
        catch (Exception e)
        {
           String emsg = 'Assignment_Groups__c query exception: ' + e.getMessage();
           System.debug(Logginglevel.ERROR, emsg);
           throw e;
        }     
      
        Set<String> gmIds = agMap.keySet();
        for (String gmId : gmIds)
        {
            Assignment_Groups__c gm = new Assignment_Groups__c(Id = gmId);
            gm.Cycle_Team__c = agMap.get(gmId);
            agsMasterUpdates.add(gm);
        }
        try
        {
            update agsMasterUpdates;
        }
        catch (Exception e)
        {
           String emsg = 'Assignment_Groups__c update exception: ' + e.getMessage();
           System.debug(Logginglevel.ERROR, emsg);
           throw e;
        }
    }
    catch (Exception e)
    {
        String emsg = 'User trigger exception: ' + e.getMessage();
        System.debug(Logginglevel.ERROR, emsg);
    }
    
    /*
       update by plo 03/17/2012
       chatter user distribution
       
       update by plo 05/15/12
       To exclude active users with termination date <= today (OOR users only) or termination date == null
    */
    if(trigger.isAfter)
    {
       Map<String,sObjectField> userFieldDecribeMap = Schema.User.getSObjectType().getDescribe().fields.getMap();
       Set<Id> uIds = new Set<Id>();
       Set<Id> asyncUIds = new Set<Id>();
       Set<String> dmlMixOpFieldsForUpdate = new Set<String>
       {
          'UserRoleId', 'IsActive', 'ForecastEnabled', 'IsPortalEnabled', 'Username', 'ProfileId'
       };
       set<String> allowedFieldsForUpdate = new Set<String>
       {
          'UserRoleId', 'IsActive', 'ProfileId', 'ManagerId'
       };
       
       for(User u : trigger.new)
       {
          Boolean isFuture = false;	
          Boolean isIncluded = false;
       	
          if(trigger.isInsert)
          {
             // call future if UserRole is not null
          	 if(u.UserRoleId != null)
          	 {
                isFuture = true;
          	 }
          	 
          	 isIncluded = true;
          }
          else if(trigger.isUpdate)
          {
          	 Set<String> updatedFields = new Set<String>();
         	 User oldU = trigger.oldMap.get(u.Id);
             // only check user sObject accessible fields
             for(String n : allowedFieldsForUpdate)
             {
                if(userFieldDecribeMap.containskey(n))
                {
                   // field was updated
	                if(u.get(n) != oldU.get(n))
	                {
	                   updatedFields .add(n);
	                }
                }
             }
             
             // at least one of the updated fields are in the allowed the field list
             if(updatedFields.size() > 0)
             {
                isIncluded = true;  
                
                // if updated fields contain ANY of the dmx mix op fields
                updatedFields.retainAll(dmlMixOpFieldsForUpdate);
                if(updatedFields.size() > 0)
                   isFuture = true;
             }
          }
          
          // only run on active users with termination date > today or termination == null
          if(isIncluded && u.IsActive && (u.Termination_Date__c > Date.today() || u.Termination_Date__c == null))
          {
	          if(isFuture)
	             asyncUIds.add(u.Id);
	          else
	             uIds.add(u.Id);
          }
       }
       
       if(!asyncUIds.isEmpty())
          ChatterUserTriggerHelper.AsyncAddUsersToChatterGroups(asyncUIds);
       else 
          ChatterUserTriggerHelper.AddUsersToChatterGroups(uIds);
    }
}